package com.chris.core.socket.netty.code;

import com.chris.core.socket.netty.dto.SocketParameterEnum;
import com.chris.core.socket.netty.dto.protocol.CustomMessageProtocol;
import com.chris.core.socket.netty.util.NettyRunTimeUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * 自定义  - 解码器
 * 只面向java to java
 * 只合适此存在单一编解码的情况（不支持多编解码）
 * 2023-5-16
 * 此方法和LengthFieldBasedFrameDecoder编解码有雷同地方
 *
 * tag: 注意控制 因为网络原因造成数据错误，可能会产生错位接收，造成下家数据转换出错的容错处理
 */
public class CustomMessageDecoder extends ByteToMessageDecoder {
    private Logger log = LoggerFactory.getLogger(this.getClass());


    /**
     * 读取文件类型(单线程内-全局变量)
     */
    int type = 0;
    /**
     * 读取内容长度(单线程内-全局变量)
     */
    int length = 0;
    /**
     * 读取步骤(单线程内-全局变量)
     * 0 读取 type 1 读取 length 2 读取content
     */
    int readsetup = 0;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
       // log.debug("decode->");

        //readableBytes() 返回表示ByteBuf当前可读取的字节数，它的值等于writerIndex减去readerIndex
        if (readsetup == 0 && in.readableBytes() >= 8) {
            //读取type
            type = in.readInt(); //这里readInt 代表读取int,4个字节
            readsetup = 1;

            //读取length
            // if (readsetup == 1 && in.readableBytes() >= 4) {
            length = in.readInt(); //这里readInt 代表读取int,4个字节
            readsetup = 2;
        }

        if (in.readableBytes() < length)
        {
            // 如果当前可读字节还未达到长度长度域的偏移，那说明肯定是读不到长度域的，直接不读
            return ;
        }
        else if (length<=0) {//readsetup==2 &&
            //读取空内容
            //恢复初始化值
            type=0;
            length=0;
            readsetup=0;
            return;
        }
        else  if (readsetup == 2 && in.readableBytes() >= length ) {
            long beginTime=System.currentTimeMillis();
            byte[] content = new byte[length];
            in.readBytes(content);
            //封装成MyMessageProtocol对象，传递到下一个handler业务处理
            CustomMessageProtocol msg = new CustomMessageProtocol();
            //messageProtocol.setType(SocketParameterEnum.get(type));
            //messageProtocol.setLen(length);
            msg.setContent(content,type);
            out.add(msg);

            //todo 需要确认 ， 并非真正消费信息 ？ 在这里做流量限制不起作用 ？ ，因为只是已经写入缓存，非常有可能 只是控制从缓存读出速度而已，直到触发缓存队列满，才全局限流
            if (type== SocketParameterEnum.FileObjectType.getCode()) {
                //只有传输文件时候，进行流量控制
                //单进程chanel总量限制，所有并发会在这里排队pieline
                //限流->  每次[5K] 发送量 -> 10240 b/ms = 10240kb/s = 10m/s(实际7.79m)  , 5120 = 5m/s(实际3.94m/s) ,20480 = 20m/s(实际20.17m/s) , 30720 = 30m/s(实际38.11)
                NettyRunTimeUtil.flowControl(length, beginTime, 20480);
            }
            //恢复初始化值
            type=0;
            length=0;
            readsetup=0;


        }
        //读取content (等待读取全部填充满length才抛出CustomMessageProtocol,否则等待继续填充)
    }
}
